
/*
 * (a)  (C) 1990 by Adobe Systems Incorporated. All rights reserved.
 *
 * (b)  If this Sample Code is distributed as part of the Display PostScript
 *	System Software Development Kit from Adobe Systems Incorporated,
 *	then this copy is designated as Development Software and its use is
 *	subject to the terms of the License Agreement attached to such Kit.
 *
 * (c)  If this Sample Code is distributed independently, then the following
 *	terms apply:
 *
 * (d)  This file may be freely copied and redistributed as long as:
 *	1) Parts (a), (d), (e) and (f) continue to be included in the file,
 *	2) If the file has been modified in any way, a notice of such
 *      modification is conspicuously indicated.
 *
 * (e)  PostScript, Display PostScript, and Adobe are registered trademarks of
 *	Adobe Systems Incorporated.
 * 
 * (f) THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO
 *	CHANGE WITHOUT NOTICE, AND SHOULD NOT BE CONSTRUED
 *	AS A COMMITMENT BY ADOBE SYSTEMS INCORPORATED.
 *	ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY
 *	OR LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO
 *	WARRANTY OF ANY KIND (EXPRESS, IMPLIED OR STATUTORY)
 *	WITH RESPECT TO THIS INFORMATION, AND EXPRESSLY
 *	DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY, 
 *	FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT
 *	OF THIRD PARTY RIGHTS.
 */

/*
*	Graphic.m
 *
 *	Version:	2.0
 *	Author:	Ken Fromm
 *	History:
 *			03-07-91		Added this comment.
*/

#import "Graphic.h"
#import "DrawingViewWraps.h"
#import <appkit/defaults.h>
#import <appkit/nextstd.h>
#import <dpsclient/wraps.h>

void initGparms(GParms *gParms)
{
	gParms->path_type = STROKE;
	gParms->color_type = GRAY;
	gParms->gray =  NX_BLACK;
	gParms->red = gParms->green = gParms->blue = NX_BLACK;
	gParms->linewidth = 1;
	gParms->miterlimit = 10;
	gParms->linejoin = gParms->linecap = 0;
}

@implementation Graphic : Object

+ new
{
	self = [super new];
	initGparms(&parms);
    
	return self;
}

- free
{
	if (path.pts)
		NX_FREE(path.pts);
	if (path.ops)
		NX_FREE(path.ops);

	return self;
}

- installGparms:(const GParms *) gParm
{
	parms = *gParm;

	return self;
}

- installUpath:(const UPath *) aUpath andBounds:(const NXRect *) aRect
{
	NX_MALLOC(path.pts, float, aUpath->num_pts+4);
	NX_MALLOC(path.ops, char, aUpath->num_ops+1);

	bcopy(aUpath->pts, &path.pts[4], aUpath->num_pts * sizeof(float)/sizeof(char));
	path.num_pts = aUpath->num_pts + 4;

	path.ops[0] = dps_ucache;
	bcopy(aUpath->ops, &path.ops[1], aUpath->num_ops);
	path.num_ops = aUpath->num_ops + 1;


	bounds = *aRect;
	path.pts[0] = bounds.origin.x;
	path.pts[1] = bounds.origin.y;
	path.pts[2] = bounds.origin.x + bounds.size.width;
	path.pts[3] = bounds.origin.y + bounds.size.height;

	return self;
}

- getBounds:(NXRect *)theRect
{
	*theRect = bounds;

	return self;
}

/* Public routines. */
- setPathType:(int) value
{
	parms.path_type = (unsigned char) value;

	return self;
}

- (int)pathType
{
	return  (int)parms.path_type;
}

- setLineWidth:(float) value
{
	parms.linewidth = value;

	return self;
}

- (float)lineWidth
{
	return parms.linewidth;
}

- setLineJoin:(int) value
{
	parms.linejoin = (unsigned char) value;

	return self;
}

- (int)lineJoin
{
	return (int) parms.linejoin;
}

- setLineCap:(int) value
{
	parms.linecap = (unsigned char) value;

	return self;
}

- (int)lineCap
{
	return (int) parms.linecap;
}

- setMiterLimit:(float) value
{
	parms.miterlimit = value;

	return self;
}

- (float) miterLimit
{
	return parms.miterlimit;
}

- (int) colorType
{
	return (int) parms.color_type;
}

- setGray:(float) value
{
	parms.gray = value;
	parms.color_type = GRAY;

	return self;
}

- (float)gray
{
	return parms.gray;
}

- setRGBColor:(int)r  : (int)g  :(int)b
{
	parms.red = r;
	parms.green = g;
	parms.blue = b;
	parms.color_type = RGB;

	return self;
}

- getRGBColor:(int *)r  : (int *)g  :(int *)b
{
	*r = parms.red;
	*g = parms.green;
	*b = parms.blue;

	return self;
}

- setHGBColor:(int)h  :(int)s  :(int)b
{
	parms.red = h;
	parms.green = s;
	parms.blue = b;
	parms.color_type = HSB;

	return self;
}

- getHGBColor:(int *)h  :(int *)s  :(int *)b
{
	*h = parms.red;
	*s = parms.green;
	*b = parms.blue;

	return self;
}

- setCMYKColor:(int)c  : (int)m :(int)y  :(int)k
{
	parms.red = c;
	parms.green = m;
	parms.blue = y;
	parms.gray = k;
	parms.color_type = CMYK;

	return self;
}

- getCMYKColor:(int *)c  : (int *)m :(int *)y  :(int *)k
{
	*c = parms.red;
	*m = parms.green;
	*y = parms.blue;
	*k = parms.gray;

	return self;
}

/* Make this external so that DrawingView can use it. */
void setGraphicState(GParms *curParms, GParms *objParms, int format)
{
	DPSContext	ctxt;
	
	ctxt = DPSGetCurrentContext();

	if (!curParms || objParms->linewidth != curParms->linewidth)
	{
		if (format == ABBR)
			PSWSetlinewidth(objParms->linewidth);
		else if (format == BOT)
		{
			DPSPrintf(ctxt, "\214");	
			DPSWriteData(ctxt, &objParms->linewidth, sizeof(float));
			DPSPrintf(ctxt, "\222\233");
		}	
		else
			PSsetlinewidth(objParms->linewidth);
	}
	if (!curParms || objParms->linejoin != curParms->linejoin)
	{
		if (format == ABBR)
			PSWSetlinejoin((int) objParms->linejoin);
		else if (format == BOT)
		{
			DPSPrintf(ctxt, "\210");	
			DPSWriteData(ctxt, &objParms->linejoin, sizeof(char));
			DPSPrintf(ctxt, "\222\232");
		}
		else
			PSsetlinejoin((int) objParms->linejoin);
	}
	if (!curParms || objParms->linecap != curParms->linecap)
	{
		if (format == ABBR)
			PSWSetlinecap((int) objParms->linecap);
		else if (format == BOT)
		{
			DPSPrintf(ctxt, "\210");	
			DPSWriteData(ctxt, &objParms->linecap, sizeof(char));
			DPSPrintf(ctxt, "\222\231");
		}
		else
			PSsetlinecap((int) objParms->linecap);
	}
	if (!curParms || objParms->miterlimit != curParms->miterlimit)
	{
		if (format == ABBR)
			PSWSetmiterlimit(objParms->miterlimit);
		else
			PSsetmiterlimit(objParms->miterlimit);
	}

	switch (objParms->color_type)
	{
		case GRAY:
			if (!curParms || objParms->gray != curParms->gray)
			{
				if (format == ABBR)
					PSWSetgray(objParms->gray);
				else if (format == BOT)
				{
					DPSPrintf(ctxt, "\214");	
					DPSWriteData(ctxt, &objParms->gray, sizeof(float));
					DPSPrintf(ctxt, "\222\226");
				}	
				else
					PSsetgray(objParms->gray);
			}
			break;
		case RGB:
			if (!curParms || objParms->red != curParms->red ||
				objParms->green != curParms->green ||
				objParms->blue != curParms->blue)
			{
				if (format == ABBR)
					PSWSetrgbcolor(objParms->red, objParms->green, objParms->blue);
				else if (format == BOT)
				{
					DPSPrintf(ctxt, "\214");	
					DPSWriteData(ctxt, &objParms->red, sizeof(float));
					DPSPrintf(ctxt, "\214");	
					DPSWriteData(ctxt, &objParms->green, sizeof(float));
					DPSPrintf(ctxt, "\214");	
					DPSWriteData(ctxt, &objParms->blue, sizeof(float));
					DPSPrintf(ctxt, "\222\235");
				}
				else
					PSsetrgbcolor(objParms->red, objParms->green, objParms->blue);
			}
			break;
		case HSB:
			if (!curParms || objParms->red != curParms->red ||
				objParms->green != curParms->green ||
				objParms->blue != curParms->blue)
			{
				if (format == ABBR)
					PSWSethsbcolor(objParms->red, objParms->green, objParms->blue);
				else if (format == BOT)
				{
					DPSPrintf(ctxt, "\214");	
					DPSWriteData(ctxt, &objParms->red, sizeof(float));
					DPSPrintf(ctxt, "\214");	
					DPSWriteData(ctxt, &objParms->green, sizeof(float));
					DPSPrintf(ctxt, "\214");	
					DPSWriteData(ctxt, &objParms->blue, sizeof(float));
					DPSPrintf(ctxt, "\222\230");
				}
				else
					PSsethsbcolor(objParms->red, objParms->green, objParms->blue);
			}
			break;
		case CMYK:
			if (!curParms || objParms->red != curParms->red ||
				objParms->green != curParms->green ||
				objParms->blue != curParms->blue ||
				objParms->gray != curParms->gray)
			{
				if (format == ABBR)
					PSWSetcmykcolor(objParms->red, objParms->green, objParms->blue,
					objParms->gray);
				else if (format == BOT)
				{
					DPSPrintf(ctxt, "\214");	
					DPSWriteData(ctxt, &objParms->red, sizeof(float));
					DPSPrintf(ctxt, "\214");	
					DPSWriteData(ctxt, &objParms->green, sizeof(float));
					DPSPrintf(ctxt, "\214");	
					DPSWriteData(ctxt, &objParms->blue, sizeof(float));
					DPSPrintf(ctxt, "\214");	
					DPSWriteData(ctxt, &objParms->gray, sizeof(float));
					DPSPrintf(ctxt, "\222\223");
				}
				else
					PSsetcmykcolor(objParms->red, objParms->green, objParms->blue,
					objParms->gray);
			}
			break;
	}

	if (curParms)
		*curParms = *objParms;
}

/*
*	Call the appropriate wrap to construct the path. Not the recommended
*	approach to drawing  paths (user paths are). 
*/
static void makeRedBook(UPath *aUpath, int format)
{
	int		i_op, i_pt;

	DPSContext	ctxt;
	
	ctxt = DPSGetCurrentContext();	

	/* Skip the ucache operator. */
	i_pt = 4;
	for (i_op = 1; i_op < aUpath->num_ops; i_op++)
	{
		switch (aUpath->ops[i_op])
		{
			case dps_moveto:
				if (format == ABBR)
					PSWMoveto(aUpath->pts[i_pt], aUpath->pts[i_pt+1]);				
				else if (format == BOT)
				{
					DPSPrintf(ctxt, "\214");	
					DPSWriteData(ctxt, &aUpath->pts[i_pt], sizeof(float));
					DPSPrintf(ctxt, "\214");	
					DPSWriteData(ctxt, &aUpath->pts[i_pt+1], sizeof(float));
					DPSPrintf(ctxt, "\222\153");
				}	
				else
					PSmoveto(aUpath->pts[i_pt], aUpath->pts[i_pt+1]);
				i_pt += 2;
				break;
			case dps_rmoveto:
				if (format == ABBR)
					PSWRmoveto(aUpath->pts[i_pt], aUpath->pts[i_pt+1]);
				else if (format == BOT)
				{
					DPSPrintf(ctxt, "\214");	
					DPSWriteData(ctxt, &aUpath->pts[i_pt], sizeof(float));
					DPSPrintf(ctxt, "\214");	
					DPSWriteData(ctxt, &aUpath->pts[i_pt+1], sizeof(float));
					DPSPrintf(ctxt, "\222\206");
				}	
				else
					PSrmoveto(aUpath->pts[i_pt], aUpath->pts[i_pt+1]);
				i_pt += 2;
				break;
			case dps_lineto:
				if (format == ABBR)
					PSWLineto(aUpath->pts[i_pt], aUpath->pts[i_pt+1]);
				else if (format == BOT)
				{
					DPSPrintf(ctxt, "\214");	
					DPSWriteData(ctxt, &aUpath->pts[i_pt], sizeof(float));
					DPSPrintf(ctxt, "\214");	
					DPSWriteData(ctxt, &aUpath->pts[i_pt+1], sizeof(float));
					DPSPrintf(ctxt, "\222\143");
				}
				else
					PSlineto(aUpath->pts[i_pt], aUpath->pts[i_pt+1]);
				i_pt += 2;
				break;
			case dps_rlineto:
				if (format == ABBR)
					PSWRlineto(aUpath->pts[i_pt], aUpath->pts[i_pt+1]);
				else if (format == BOT)
				{
					DPSPrintf(ctxt, "\214");	
					DPSWriteData(ctxt, &aUpath->pts[i_pt], sizeof(float));
					DPSPrintf(ctxt, "\214");	
					DPSWriteData(ctxt, &aUpath->pts[i_pt+1], sizeof(float));
					DPSPrintf(ctxt, "\222\205");
				}
				else
					PSrlineto(aUpath->pts[i_pt], aUpath->pts[i_pt+1]);
				i_pt += 2;
				break;
			case dps_curveto:
				if (format == ABBR)
					PSWCurveto(aUpath->pts[i_pt], aUpath->pts[i_pt+1],
						aUpath->pts[i_pt+2], aUpath->pts[i_pt+3],
						aUpath->pts[i_pt+4], aUpath->pts[i_pt+5]);
				else if (format == BOT)
				{
					DPSPrintf(ctxt, "\214");	
					DPSWriteData(ctxt, &aUpath->pts[i_pt], sizeof(float));
					DPSPrintf(ctxt, "\214");	
					DPSWriteData(ctxt, &aUpath->pts[i_pt+1], sizeof(float));
					DPSPrintf(ctxt, "\214");	
					DPSWriteData(ctxt, &aUpath->pts[i_pt+ 2], sizeof(float));
					DPSPrintf(ctxt, "\214");	
					DPSWriteData(ctxt, &aUpath->pts[i_pt+3], sizeof(float));
					DPSPrintf(ctxt, "\214");	
					DPSWriteData(ctxt, &aUpath->pts[i_pt+4], sizeof(float));
					DPSPrintf(ctxt, "\214");	
					DPSWriteData(ctxt, &aUpath->pts[i_pt+5], sizeof(float));

					DPSPrintf(ctxt, "\222\053");
				}
				else
					PScurveto(aUpath->pts[i_pt], aUpath->pts[i_pt+1],
						aUpath->pts[i_pt+2], aUpath->pts[i_pt+3],
						aUpath->pts[i_pt+4], aUpath->pts[i_pt+5]);
				i_pt += 6;
				break;
			case dps_rcurveto:
				if (format == ABBR)
					PSWRcurveto(aUpath->pts[i_pt], aUpath->pts[i_pt+1],
						aUpath->pts[i_pt+2], aUpath->pts[i_pt+3],
						aUpath->pts[i_pt+4], aUpath->pts[i_pt+5]);
				else if (format == BOT)
				{
					DPSPrintf(ctxt, "\214");	
					DPSWriteData(ctxt, &aUpath->pts[i_pt], sizeof(float));
					DPSPrintf(ctxt, "\214");	
					DPSWriteData(ctxt, &aUpath->pts[i_pt+1], sizeof(float));
					DPSPrintf(ctxt, "\214");	
					DPSWriteData(ctxt, &aUpath->pts[i_pt+ 2], sizeof(float));
					DPSPrintf(ctxt, "\214");	
					DPSWriteData(ctxt, &aUpath->pts[i_pt+3], sizeof(float));
					DPSPrintf(ctxt, "\214");	
					DPSWriteData(ctxt, &aUpath->pts[i_pt+4], sizeof(float));
					DPSPrintf(ctxt, "\214");	
					DPSWriteData(ctxt, &aUpath->pts[i_pt+5], sizeof(float));

					DPSPrintf(ctxt, "\222\172");
				}
				else
					PSrcurveto(aUpath->pts[i_pt], aUpath->pts[i_pt+1],
						aUpath->pts[i_pt+2], aUpath->pts[i_pt+3],
						aUpath->pts[i_pt+4], aUpath->pts[i_pt+5]);
				i_pt += 6;
				break;
			case dps_closepath:
				if (format == ABBR)
					PSWClosepath();
				else if (format == BOT)
					DPSPrintf(ctxt, "\222\026");
				else
					PSclosepath();
				break;
		}
	}
}

/*
 * Draws the graphic.
 */
- drawObject:(NXRect *) r  currentParms:(GParms *) gParms withFormat:(int) format
{
	DPSContext	ctxt;
	
	ctxt = DPSGetCurrentContext();	
	
	if (!r || NXIntersectsRect(r, &bounds))
	{
		setGraphicState(gParms, &parms, format);
		makeRedBook(&path, format);
		if (parms.path_type == FILL)
		{
			if (format == ABBR)
				PSWFill();
			else if (format == BOT)
				DPSPrintf(ctxt, "\222\102");	
			else
				PSfill();
		}
		else
		{
			if (format == ABBR)
				PSWStroke();
			else if (format == BOT)
				DPSPrintf(ctxt, "\222\247");	
			else
				PSstroke();
		}
	}

	return self;
}

@end

